﻿using System;
using System.Threading.Tasks;
using Microsoft.Extensions.Caching.Memory;

namespace housingsafety.server.Caching.Core
{
    public class MemoryCacheFacade : ICache
    {
        private readonly IMemoryCache m_MemoryCache;
        private readonly string m_Name;

        public string Name { get { return m_Name; } }

        public MemoryCacheFacade(IMemoryCache memoryCache, string name = null)
        {
            m_MemoryCache = memoryCache;
            m_Name = name ?? string.Empty;
        }

        public TItem Get<TItem>(string key)
        {
            key = CreateCacheKeyString(key);
            return m_MemoryCache.Get<TItem>(key);
        }

        public Task<TItem> GetAsync<TItem>(string key)
        {
            key = CreateCacheKeyString(key);
            return Task.FromResult(m_MemoryCache.Get<TItem>(key));
        }

        public object Get(string key, Type type = null)
        {
            key = CreateCacheKeyString(key);
            return m_MemoryCache.Get(key);
        }

        public Task<object> GetAsync(string key, Type type = null)
        {
            key = CreateCacheKeyString(key);
            return Task.FromResult(m_MemoryCache.Get(key));
        }

        public void Remove(string key)
        {
            key = CreateCacheKeyString(key);
            m_MemoryCache.Remove(key);
        }

        public Task RemoveAsync(string key)
        {
            key = CreateCacheKeyString(key);
            m_MemoryCache.Remove(key);
            return Task.CompletedTask;
        }

        public void Set<TItem>(string key, TItem value, CacheEntryOptions options = null)
        {
            key = CreateCacheKeyString(key);
            m_MemoryCache.Set(key, value, new MemoryCacheEntryOptions
            {
                AbsoluteExpiration = options?.AbsoluteExpiration,
                AbsoluteExpirationRelativeToNow = options?.AbsoluteExpirationRelativeToNow,
                SlidingExpiration = options?.SlidingExpiration
            });
        }

        public Task SetAsync<TItem>(string key, TItem value, CacheEntryOptions options = null)
        {
            key = CreateCacheKeyString(key);
            m_MemoryCache.Set(key, value, new MemoryCacheEntryOptions
            {
                AbsoluteExpiration = options?.AbsoluteExpiration,
                AbsoluteExpirationRelativeToNow = options?.AbsoluteExpirationRelativeToNow,
                SlidingExpiration = options?.SlidingExpiration
            });
            return Task.CompletedTask;
        }

        private string CreateCacheKeyString(string key)
        {
            return CacheKey.NewCacheKeyString(m_Name, key);
        }

        public T GetOrDb<T>(string v, Func<string, T> p)
        {
            var t = Get<T>(v);
            if (null == t)
            {
                return p.Invoke(v);
            }

            return t;
        }
    }
}
